Game Server Services(GS2)のUnityチュートリアルをUniTaskで実装してみる
こんにちは、ゲームソリューション部の入井です。
GS2の公式サイトでは、GS2のUnity SDKを利用開始するためのチュートリアルが公開されています。
こちらのチュートリアルでは実際のC#コードも紹介されていますが、非同期処理がコルーチンで実装されており少しコードが複雑になっています。
GS2のUnity SDKには、UniTaskライブラリと連携して使うための専用メソッドが用意されており、これを使用することでコードをより簡潔に書くことができます。
そこで、今回はチュートリアルのコードにUniTaskを適用し、実際にUnity上で動かすまでの流れをご紹介します。
UniTaskについての詳しい情報は以下の記事などをご参照ください。
環境
- Unity 2022.3.14f1
- UniTask 2.5.0
- GS2 C# SDK 2023.12.10
- GS2 SDK for Unity 2023.12.14
GS2関係のセットアップ
事前に以下のようなセットアップが必要ですが、これらについては公式チュートリアル通りにセットアップを進めれば問題ありません。
- GS2アカウント作成
- マネージメントコンソールでのプロジェクト作成
- GS2 SDK for Unityのインストール
- UIkit for Unityは今回は不要
- APIキーの作成
- GS2-DeployによるGS2-Accountのリソース作成
UniTaskのセットアップ
UniTaskを使用するには、Unityプロジェクトにライブラリをインストールする必要があります。このようなライブラリを導入する際、配布されているunitypackageでのインポートする方法がよく利用されますが、今回の場合はパッケージマネージャ経由でライブラリをインストールしないと、GS2のSDKで用意されているUniTask用のメソッドが使用できないためご注意ください。
理由として、GS2のSDKのソースコードを見ると、UniTask用のメソッドは以下のように#if
プリプロセッサでコンパイルの対象に含めるかどうかを制御しています。
**#if GS2_ENABLE_UNITASK** public static async UniTask<Gs2Domain> CreateAsync( IGs2Credential credential, Region region = Region.ApNortheast1, string distributorNamespaceName = "default" ) { var connection = new Gs2Connection( credential, region ); await connection.ConnectAsync(); return new Gs2Domain( connection, distributorNamespaceName ); } **#endif**
評価対象のGS2_ENABLE_UNITASK
シンボルは、GS2 SDKのルートにあるGs2.Unity.asmdef
の"versionDefines"
プロパティにて、以下のようにパッケージマネージャにUniTaskが存在する時のみ定義されるようになっています。
{ "name": "com.cysharp.unitask", "expression": "", "define": "GS2_ENABLE_UNITASK" }
unitypackageインポートでもUniTaskは使えますが、パッケージマネージャにUniTaskが追加されるわけではないため、GS2 SDKのUniTask専用のメソッドが使用できないというわけです。
なお、パッケージマネージャ経由のUniTaskのインストールは、以下のようにGitHubリポジトリURLを指定すると簡単にインストールできます。
GitHub - Cysharp/UniTask: Provides an efficient allocation free async/await integration for Unity.
実装
準備ができたので早速コードを実装します。
全体的な処理の流れとしては以下のようになっています。
- ゲームの起動
- GS2-Accountにアクセスして匿名アカウント新規作成
- 作成した匿名アカウントへのログイン処理
- ログイン先からの情報出力
GameObjectの用意
最初に、Gs2ScriptTestというスクリプトファイルを作成します。今回のコードは全てこのファイルに書いていきます。
そして、ヒエラルキーツリー上で空のGameObjectを作成し、Gs2ScriptTestファイルをアタッチします。
スクリプトファイルへソースコード追加
Gs2ScriptTestファイルでは、Start()
メソッド内に以下のようにコードを書きます。これにより、ゲームの起動と同時にGS2-Accoutへのアカウント作成やログインなどの処理が実行されます。
using Gs2.Core.Model; using Gs2.Unity.Util; using UnityEngine; public class Gs2ScriptTest : MonoBehaviour { // Start is called before the first frame update async void Start() { // 変数宣言 var clientId = "YourClientId"; var clientSecret = "YourClientSecret"; var accountNamespaceName = "game-0001"; // GS2 SDK初期化 var gs2 = await Gs2.Unity.Core.Gs2Client.CreateAsync( new BasicGs2Credential( clientId, clientSecret ), Region.ApNortheast1 ); // GS2-Account Namespaceの定義 var gs2Account = gs2.Account.Namespace(accountNamespaceName); // 匿名アカウントの新規作成 var account = await (await gs2Account.CreateAsync()).ModelAsync(); // 作成した匿名アカウント情報の出力 Debug.Log($"作成したアカウントのuserId: {account.UserId}"); Debug.Log($"作成したアカウントのpassword: {account.Password}"); // 作成した匿名アカウントでのログイン var gameSession = await gs2.LoginAsync( new Gs2AccountAuthenticator(new AccountSetting { accountNamespaceName = accountNamespaceName }), account.UserId, account.Password ); // ログイン先ユーザーID出力 var userId = gs2Account.Me(gameSession).UserId; Debug.Log($"ログインによって取得したuserId: {userId}"); } }
このコードは、公式チュートリアルで公開されているコードとほぼ同じ動きをするものですが、UniTaskを使うことでかなり書き方がシンプルになっています。また、最後の方の処理を少し変えています。
GS2 SDKの初期化
ここからは、上記コードの各処理で具体的に何が行われているのかを解説していきます。
// 変数宣言 var clientId = "YourClientId"; var clientSecret = "YourClientSecret"; var accountNamespaceName = "game-0001"; // GS2 SDK初期化 var gs2 = await Gs2.Unity.Core.Gs2Client.CreateAsync( new BasicGs2Credential( clientId, clientSecret ), Region.ApNortheast1 );
こちらでは、SDKの初期化を行っています。
CreateAsync()
に認証とリージョンの情報を渡すことで、Gs2Domein
というオブジェクトが取得できます。このオブジェクトはGS2 SDKの最も中心的な存在で、各サービスのAPIへアクセスする際に毎回使用します。
認証のために使用しているclientId
, clientSecret
は、事前準備の際にGS2-Identifierで作成したユーザーのクレデンシャル情報です。SDKからアクセスできるサービスやリソースは、ユーザー作成時に設定した権限の内容に左右されます。
匿名アカウントの新規作成
// 匿名アカウントの新規作成 var account = await (await gs2Account.CreateAsync()).ModelAsync(); // 作成した匿名アカウント情報の出力 Debug.Log($"作成したアカウントのuserId: {account.UserId}"); Debug.Log($"作成したアカウントのpassword: {account.Password}");
最初に匿名アカウントをCreateAsync()
で作成し、そのアカウントの情報をModelAsync()
で取得しています。その後、取得したアカウントのユーザーID、パスワードがコンソールに出力されます。
匿名アカウントとは、一般的なアカウントと異なりIDとパスワードがシステムによってランダムで決定されるアカウントです。ユーザーの識別機能は維持しつつ、各ユーザーが複雑な登録処理を行わなくてもすぐにゲームを開始できることが特徴です。よくある使い方として、ゲーム初回起動時にアカウントを自動的に新規作成し、その際ランダムに発行されたID・パスワードはデバイスに保管しておき、次回ゲーム起動時にそれらの保存された認証情報を使って裏側でログインする、というものがあります。これにより、ユーザーに認証を意識させることなくゲームクライアントから各ユーザー用のデータへの安全なアクセスが実現できます。
上記のようなアカウントであるため、CreateAsync()
ではIDなどの引数を渡すことなくアカウントの作成が行われています。その後にコンソール出力されるID・パスワードも完全にランダム文字列になっています。
ログイン処理とログイン先からの情報出力
// 作成した匿名アカウントでのログイン var gameSession = await gs2.LoginAsync( new Gs2AccountAuthenticator(new AccountSetting { accountNamespaceName = accountNamespaceName }), account.UserId, account.Password ); // ログイン先ユーザーID出力 var userId = gs2Account.Me(gameSession).UserId; Debug.Log($"ログインによって取得したuserId: {userId}");
LoginAsync()
で先ほど作成した匿名アカウントのID・パスワードを渡すことでログインを行い、その結果作成されたセッション情報をgameSession
変数へ格納しています。第一引数にGs2AccountAuthneticator
というオブジェクトを渡していますが、これはGS2の認証システムを使用することを表しています。Gs2AccountAuthneticator
にはIAuthenticator
というインターフェースが使われており、これを使うことでGS2とは別の認証基盤による認証を実装することもできます。
gs2Account.Me(gameSession).UserId
によりログイン先のユーザーのIDを取得し、その結果をコンソール出力しています。
元のチュートリアルでは引き継ぎ情報という別のデータを出力していましたが、アカウント作成した段階では引き継ぎ情報はセットされておらず、処理も少し複雑になってしまうため、私の場合はユーザーIDをログイン先から取得する形に変更しました。当然、アカウント作成時に出力したユーザーIDと同じ値になっています。
まとめ
GS2公式チュートリアルのコードをUniTaskを使用したものに実装し直してみました。これにより、更にシンプルなコードで認証関係の処理を書くことができました。
GS2を使用することで、認容関係のような複雑な実装になりがちな要件についても、このように簡単にゲームに組み込むことができます。